# This file is part of OrangeSpider. OrangeSpider is a meta model based
# development tool.
# 
# OrangeSpider is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# OrangeSpider is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with OrangeSpider.  If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2009 Stefan Nikolaus <OrangeSpiderMaster@googlemail.com>

# Find non aggregated meta class. These meta classes
# can be edited directly with the extension list
from MetaModel import *
import random

class Walker:
    def __init__(self, repository, visitor):
        self.repository = repository
        self.visitor = visitor

    """
    A full walk iterates through the whole meta model in the order of definition:
    first the metamodel, then the types, then the metaclasses/metaassocs
    and at last the classes and assocs
    """
    def fullWalk(self):
        visitor = self.visitor
        visitor.visitMetaModel(self.repository)
        rep = self.repository
        for mt in rep.eachMetaType():
            visitor.visitMetaType(mt)
            if mt.isMetaEnum():
                for mat in mt.eachMetaAtom():
                    visitor.visitMetaAtom(mat)
        for mc in rep.eachMetaClass():
            visitor.visitMetaClass(mc)
            for mp in mc.eachMetaProperty():
                visitor.visitMetaProperty(mp)
            for c in mc.eachClass():
                visitor.visitClass(c)
        for ma in rep.eachMetaAssoc():
            visitor.visitMetaAssoc(ma)
            for mp in ma.eachMetaProperty():
                visitor.visitMetaProperty(mp)
            for a in ma.eachAssoc():
                visitor.visitAssoc(a)

    """
    Walks only through the MetaClasses and then through the MetaAssocs
    """
    def metaEntityWalk(self):
        visitor = self.visitor
        rep = self.repository
        for mc in rep.eachMetaClass():
            visitor.visitMetaClass(mc)
        for ma in rep.eachMetaAssoc():
            visitor.visitMetaAssoc(ma)

def getNonAggregatedMetaClasses(rep):
    list = []
    for mc in rep.eachMetaClass():
        list.append(mc["Name"])
    for ma in rep.eachMetaAssoc():
        if ma["Aggregation"]:
            if ma.target["Name"] in list:
                if ma["SourceCardinality"] == ONE:
                    list.remove(ma.target["Name"])
    return list

def copyDict(source, target):
    for (key, value) in source.iteritems():
        target[key] = value

def cloneMetaModel(rep, targetrep):
        
    """ Does a full deep copy of a meta model into a new one.
    The new one may have extended structures."""
    assert(rep)
    assert(targetrep)
    assert(rep["Type"] == targetrep["Type"])
    majorVersion = targetrep["MajorVersion"]
    minorVersion = targetrep["MinorVersion"]
    oldWatcher = targetrep.watcher
    targetrep.watcher = None
    targetrep.currentId = rep.currentId
    copyDict(rep, targetrep)

    for mt in rep.eachMetaType():
        if mt.isMetaEnum():
            newMe = targetrep.MetaEnum(mt["Name"], mt["DefaultValue"])
            copyDict(mt, newMe)
            for mat in mt.eachMetaAtom():
                newMat = targetrep.MetaAtom(mt["Name"], mat["Name"])
                copyDict(mat, newMat)
        else:
            newMt = targetrep.MetaType(mt["Name"], mt["DefaultValue"])
            copyDict(mt, newMt)

    for mc in rep.eachMetaClass():
        newMc = targetrep.MetaClass(mc["Name"])
        copyDict(mc, newMc)
        for mp in mc.eachMetaProperty():
            newMp = targetrep.MetaProperty(mc["Name"], mp["Name"],
                                           mp.metaType["Name"])
            copyDict(mp, newMp)
        for c in mc.eachClass():
            newC = targetrep.Class(mc["Name"], c["Id"])
            copyDict(c, newC)
        
    for ma in rep.eachMetaAssoc():
        newMa = targetrep.MetaAssoc(ma["Name"])
        copyDict(ma, newMa)
        for mp in ma.eachMetaProperty():
            newMp = targetrep.MetaProperty(ma["Name"], mp["Name"],
                                           mp.metaType["Name"])
            copyDict(mp, newMp)
        for a in ma.eachAssoc():
            newSource = targetrep.access(Entity.CLASS, (ma["SourceName"],
                                                        a.source["Id"]))
            newTarget = targetrep.access(Entity.CLASS, (ma["TargetName"],
                                                        a.target["Id"]))
            newA = targetrep.Assoc(newSource, newTarget, ma["Name"], a["Id"])
                                         
    # restore original watcher and version of the now filled target metamodel
    targetrep.watcher = rep.watcher
    targetrep["MajorVersion"] = majorVersion
    targetrep["MinorVersion"] = minorVersion
    

class RandomCreatorVisitor:
    pictString = "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x1e\x00\x00\x00" \
                 + "\x1e\x08\x02\x00\x00\x00\xb4R9\xf5\x00\x00\x00\x01sRGB\x00\xae" \
                 + "\xce\x1c\xe9\x00\x00\x00\x04gAMA\x00\x00\xb1\x8f\x0b\xfca\x05" \
                 + "\x00\x00\x00 cHRM\x00\x00z&\x00\x00\x80\x84\x00\x00\xfa\x00\x00" \
                 + "\x00\x80\xe8\x00\x00u0\x00\x00\xea`\x00\x00:\x98\x00\x00\x17p" \
                 + "\x9c\xbaQ<\x00\x00\x00\tpHYs\x00\x00\x0e\xc4\x00\x00\x0e\xc4\x01" \
                 + "\x95+\x0e\x1b\x00\x00\x00bIDATHK\xed\x93A\n\x00 \x08\x04\xed\xff" \
                 + "\x8f6C\x12\x8bN\xe1\n\x82\xd2!\x10\x06q\xd6A\x80bf\xa3\xca/\xf0" \
                 + "\x91\xa0\x8d\x1e\xc8]\xf3\xd6D{}\xc1\x0bIB\x03\x02\xa8H\x15\xfa" \
                 + "\xac\x8f\xee1f\xa3\xdd\x89\xc3\x04\xb6\xc6\x9d\xb3\xac\xf0\x01U" \
                 + "\xf6\xc9\\'\x03\\Hk\xcc\xdbuA\x8d6r|Np\xe8\tG\x8b>\n\xbb\x89\x80" \
                 + "\xfd\x00\x00\x00\x00IEND\xaeB`\x82"
    def __init__(self, mm, numberOfInstances):
        self.mm = mm
        self.numberOfInstances = numberOfInstances
        self.accessMap = {}
    def visitMetaClass(self, mc):
        indexMap = []
        self.accessMap[mc["Name"]] = indexMap
        for i in range(0, self.numberOfInstances):
            c = self.mm.Class(mc["Name"])
            indexMap.append(c)
            self._fillProps(c)
    def visitMetaAssoc(self, ma):
        for i in range(0, self.numberOfInstances):
            r = random.randint(0, self.numberOfInstances - 1)
            source = self.accessMap[ma.source["Name"]][r]
            r = random.randint(0, self.numberOfInstances - 1)
            target = self.accessMap[ma.target["Name"]][r]
            a = self.mm.Assoc(source, target, ma["Name"])
            self._fillProps(a)
    def _name(self, len):
        s = ""
        for i in range(0, len):
            s += random.choice("abcdefghijklmnopqrstuvwxyzaaeeiioouuddmmnnbbgg")
        return s
    def _fillProps(self, entity):
        me = entity.intention
        for mp in me.eachMetaProperty():
            name = mp["Name"]
            if name != "Id":
                metaTypeName = mp.metaType["Name"]
                if metaTypeName == "String":
                    n = self._name(random.randint(5,10))
                    if random.randint(0,1) == 1:
                        n = n.capitalize()
                    entity[name] = n
                elif metaTypeName == "Integer":
                    entity[name] = random.randint(0,5000000)
                elif metaTypeName == "Boolean":
                    if random.randint(0,1) == 1:
                        entity[name] = True
                    else:
                        entity[name] = False
                elif metaTypeName == "Float":
                    entity[name] = round(random.uniform(0,5000000), 4)
                elif metaTypeName == "Picture":
                    entity[name] = RandomCreatorVisitor.pictString
                elif metaTypeName == "Text":
                    s = ""
                    sep = ""
                    for i in range(0, random.randint(0,30)):
                        n = self._name(random.randint(5, 13))
                        if random.randint(0,1) == 1:
                            n = n.capitalize()
                        s += sep + n
                        sep = random.choice("           \n\n,,,..")
                    entity[name] = s
                elif metaTypeName == "DateTime":
                    d = (1980 + random.randint(0, 50),
                         random.randint(1,13),
                         random.randint(1,29),
                         random.randint(0,24),
                         random.randint(0,60),
                         random.randint(0,60))
                    entity[name] = d
                elif metaTypeName == "TimeStamp":
                    entity[name] = ""
                elif metaTypeName == "Color":
                    c = (random.randint(0,256),
                         random.randint(0,256),
                         random.randint(0,256),
                         random.randint(0,256))
                    entity[name] = c
                elif metaTypeName == "Font":
                    entity[name] = "Courier"
                elif metaTypeName == "Blob":
                    s = ""
                    for i in xrange(30 + random.randint(0,600)):
                        s += chr(random.choice(range(0,255)))
                    entity[name] = s
                elif metaTypeName == "FileString":
                    s = "C:\\Test\\"
                    s += self._name(random.randint(10, 30))
                    s += "."
                    s += self._name(3)                    
                    entity[name] = s
                elif metaTypeName == "Directory":
                    s = "C:\\Test\\"
                    s += self._name(random.randint(10, 30))
                    entity[name] = s
                elif metaTypeName == "Size":
                    s = (round(random.uniform(0, 1000), 3),
                         round(random.uniform(0, 1000), 3))
                    entity[name] = s
                elif metaTypeName == "Point":
                    s = (round(random.uniform(-1000, 1000), 3),
                         round(random.uniform(-1000, 1000), 3))
                    entity[name] = s
                elif metaTypeName == "Rect":
                    s = (round(random.uniform(-1000, 1000)),
                         round(random.uniform(-1000, 1000)),
                         round(random.uniform(0, 300)),
                         round(random.uniform(0, 300)))
                    entity[name] = s
                elif metaTypeName == "Flags":
                    entity[name] = 0
                elif metaTypeName == "Url":
                    s = "http://www."
                    s += self._name(random.randint(4,15))
                    s += ".com/"
                    for i in range(0,3):
                        s += self._name(random.randint(4,15))
                        s += "/"
                        s += self._name(random.randint(10, 30))
                        s += ".html"
                    entity[name] = s
                else:
                    if mp.metaType.isMetaEnum():
                        metaAtoms = mp.metaType.metaAtoms
                        idx = random.randint(0, len(metaAtoms) - 1) 
                        mat = metaAtoms.values()[idx]
                        entity[name] = mat["Name"]                        
                        
                    else:
                        assert(False)
    
def randomFill(mm, numberOfInstances):
    visitor = RandomCreatorVisitor(mm, numberOfInstances)
    walker = Walker(mm, visitor)
    walker.metaEntityWalk()
